package com.example.base.repository;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import com.example.base.RequestQuery;
import org.springframework.data.domain.*;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;


public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

    //实体管理类，对持久化实体做增删改查，自动义sq操作模板所需要的核心类
    public final EntityManager entityManager;

    public BaseRepositoryImpl(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
        super(entityInformation, entityManager);
        this.entityManager = entityManager;
    }
    @Override
    public  List<T> findByRequestQuery(RequestQuery query)
    {

        return findByRequestQuery(query,false);
    }
    @Override
    public  List<T> findByRequestQueryOr(RequestQuery query)
    {

        return  findByRequestQueryOr(query,false);
    }
    @Override
    public  List<T> findByRequestQuery(RequestQuery query,Boolean pagesplit)
    {
        List<T> mlist=null;

        Specification<T> spec=new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate predicate=criteriaBuilder.conjunction();
                Map<String, Object>  obj=query.getQueryParam();
                for( Map.Entry<String, Object>  entity:obj.entrySet()) {
                    predicate.getExpressions().add(criteriaBuilder.equal(root.get(entity.getKey()),entity.getValue()));
                }
                return predicate;
            }
        };
        if(pagesplit) {
            Pageable pageable;
            if(query.getSort()!=null)
                pageable = PageRequest.of(query.getPage(),query.getRows(),new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
            else
                pageable = PageRequest.of(query.getPage(),query.getRows());
            Page<T> list = findAll(spec, pageable);
            mlist=list.getContent();
        }
        else
        {
            if(query.getSort()!=null)
            {
                mlist = findAll(spec,new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
            }
            else
                mlist = findAll(spec);
        }
        return mlist;
    }
    @Override
   public  List<T> findByRequestQueryAndOR(RequestQuery query,HashMap<String,Object> orRelation,Boolean pagesplit)
    {
        List<T> mlist=null;
        Specification<T> spec=new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                List<Predicate> listPredicate=new ArrayList<>();
                Predicate predicate=criteriaBuilder.conjunction();
                Map<String, Object>  obj=query.getQueryParam();
                for( Map.Entry<String, Object>  entity:obj.entrySet()) {
                    predicate.getExpressions().add(criteriaBuilder.equal(root.get(entity.getKey()),entity.getValue()));
                }
                Predicate[] predicatesArr=new Predicate[listPredicate.size()];

                for( Map.Entry<String, Object>  entity:obj.entrySet()) {
                    listPredicate.add(criteriaBuilder.equal(root.get(entity.getKey()),entity.getValue()));
                }
                predicatesArr=new Predicate[listPredicate.size()];
                Predicate predicateOr= criteriaBuilder.or(listPredicate.toArray(predicatesArr));
                return criteriaBuilder.or(predicate,predicateOr);
            }
        };
        if(pagesplit) {
            Pageable pageable;
            if(query.getSort()!=null)
                pageable = PageRequest.of(query.getPage(),query.getRows(),new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
            else
                pageable = PageRequest.of(query.getPage(),query.getRows());
            Page<T> list = findAll(spec, pageable);
            mlist=list.getContent();
        }
        else {
            if(query.getSort()!=null)
            {
                mlist = findAll(spec,new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
            }
            else
                mlist = findAll(spec);
        }
        return mlist;
    }
    @Override
    public  List<T> findByRequestQueryOr(RequestQuery query,Boolean pagesplit)
    {

        List<T> mlist=null;
        Specification<T> spec=new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {

                List<Predicate> listPredicate=new ArrayList<>();
                Map<String, Object>  obj=query.getQueryParam();
                for( Map.Entry<String, Object>  entity:obj.entrySet()) {
                    listPredicate.add(criteriaBuilder.equal(root.get(entity.getKey()),entity.getValue()));
                }
                Predicate[] predicatesArr=new Predicate[listPredicate.size()];
                Predicate predicate= criteriaBuilder.or(listPredicate.toArray(predicatesArr));
                return predicate;
            }
        };
        if(pagesplit) {
            Pageable pageable;
            if(query.getSort()!=null)
                pageable = PageRequest.of(query.getPage(),query.getRows(),new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
             else
              pageable = PageRequest.of(query.getPage(),query.getRows());
            Page<T> list = findAll(spec, pageable);
            mlist=list.getContent();
        }
        else {
            if(query.getSort()!=null)
            {
                mlist = findAll(spec,new Sort(query.getOrder()=="desc"?Direction.DESC:Direction.ASC,query.getSort()));
            }
             else
              mlist = findAll(spec);
        }
        return mlist;
    }
    @Override
    public List<T> findObjectLike(String key,String like)
    {
        List<T> list=findAll(new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                Predicate predicate=criteriaBuilder.like(root.get(key),like);

                return predicate;
            }
        });
        return list;

    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findBySql(String sql) {
        return entityManager.createNativeQuery(sql).getResultList();
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> findByHQL(String hql) {
        return entityManager.createQuery(hql).getResultList();
    }
    @Override
    public List<T> findBySqlArg(String sql, Object...args)
    {
        Query query = entityManager.createNativeQuery(sql);
        int i = 0;
        for(Object arg : args) {
            query.setParameter(++i, arg);
        }
       return query.getResultList();
    }
    @Override
    public void updateBySql(String sql, Object...args) {
        Query query = entityManager.createNativeQuery(sql);
        int i = 0;
        for(Object arg : args) {
            query.setParameter(++i, arg);
        }
        query.executeUpdate();
    }

    @Override
    public void updateByHql(String hql, Object...args) {
        Query query = entityManager.createQuery(hql);
        int i = 0;
        for(Object arg : args) {
            query.setParameter(++i, arg);
        }

        query.executeUpdate();
    }
    public List<T> findALLSql() {
        //根据地址分组查询，并且学生数量大于3的所有地址
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        Class<T> domainClass= getDomainClass();
        CriteriaQuery<T> query = builder.createQuery(domainClass);
        Root<T> root = query.from(domainClass);

        query.select(root);
        /*
        query.multiselect(root.get("address"),builder.count(root.get("id")))
                .groupBy(root.get("address")).having(builder.gt(builder.count(root.get("id")),3));*/

        return entityManager.createQuery(query).getResultList();
    }

 /*  public  Boolean deleteItemByParams(RequestQuery query)
   {
               Specification<T> spec=new Specification<T>() {
                   @Override
                   public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                       Predicate predicate=criteriaBuilder.conjunction();
                       Map<String, Object>  obj=query.getQueryParam();
                       for( Map.Entry<String, Object>  entity:obj.entrySet()) {
                           predicate.getExpressions().add(criteriaBuilder.equal(root.get(entity.getKey()),entity.getValue()));
                       }
                       return predicate;
                   }
               };
               return true;

   }
   public  Boolean deleteItemByParamsOr(RequestQuery query)
    {
        CriteriaBuilder builder = entityManager.getCriteriaBuilder();
        Class<T> domainClass= getDomainClass();




        return true;
    }*/



}